/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.SecretKeySpec;
/**
 *
 * @author epindado
 */
public class PruebasRSA {
    
    Cipher pkCipher, aesCipher;
    byte[] aesKey;
    SecretKeySpec aeskeySpec;
    public static final int AES_Key_Size = 256;

  public static void main(String[] args) throws Exception {
      //RSANoRandom();
      RSARandom();
  }
  
  public static void RSANoRandom () throws Exception{
    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

    byte[] input = "hola".getBytes();
    Cipher cipher = Cipher.getInstance("RSA/None/NoPadding", "BC");

    KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC");
    RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(
        "12345678", 256), new BigInteger("11", 256));
    RSAPrivateKeySpec privKeySpec = new RSAPrivateKeySpec(new BigInteger(
        "12345678", 256), new BigInteger("12345678", 256));

    RSAPublicKey pubKey = (RSAPublicKey) keyFactory.generatePublic(pubKeySpec);
    RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(privKeySpec);

    // Encriptación con clave privada
    cipher.init(Cipher.ENCRYPT_MODE, pubKey);
    byte[] cipherText = cipher.doFinal(input);
    System.out.println("cipher: " + new String(cipherText));

    //Desencriptacion con clave publica
    cipher.init(Cipher.DECRYPT_MODE, privKey);
    byte[] plainText = cipher.doFinal(cipherText);
    System.out.println("plain : " + new String(plainText));
  }
  
  public static void RSARandom() throws Exception {
    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

    byte[] input = "hola".getBytes();
    Cipher cipher = Cipher.getInstance("RSA/None/NoPadding", "BC");
    SecureRandom random = new SecureRandom();
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC");

    generator.initialize(256, random);
    KeyPair pair = generator.generateKeyPair();
    Key pubKey = pair.getPublic();
    Key privKey = pair.getPrivate();

    cipher.init(Cipher.ENCRYPT_MODE, pubKey, random);

    byte[] cipherText = cipher.doFinal(input);
    System.out.println("cipher: " + new String(cipherText));
    cipher.init(Cipher.DECRYPT_MODE, privKey);
    byte[] plainText = cipher.doFinal(cipherText);
    System.out.println("plain : " + new String(plainText));
  }
  
  /*
   * So that the files can be decrypted later, the AES key is encrypted to a file using the RSA cipher. 
   * The RSA public key is assumed to be stored in a file.
   */
  public void saveKey(File out, File publicKeyFile) throws IOException, GeneralSecurityException {
    // read public key to be used to encrypt the AES key
    byte[] encodedKey = new byte[(int)publicKeyFile.length()];
    new FileInputStream(publicKeyFile).read(encodedKey);
    
    // create public key
    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    PublicKey pk = kf.generatePublic(publicKeySpec);
    
    // write AES key
    pkCipher.init(Cipher.ENCRYPT_MODE, pk);
    CipherOutputStream os = new CipherOutputStream(new FileOutputStream(out), pkCipher);
    os.write(aesKey);
    os.close();
  }
/*
 * Before decryption can take place, the encrypted AES key must be decrypted using the RSA private key:
*/
  public void loadKey(File in, File privateKeyFile) throws GeneralSecurityException, IOException {
    // read private key to be used to decrypt the AES key
    byte[] encodedKey = new byte[(int)privateKeyFile.length()];
    new FileInputStream(privateKeyFile).read(encodedKey);
    
    // create private key
    PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedKey);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    PrivateKey pk = kf.generatePrivate(privateKeySpec);
    
    // read AES key
    pkCipher.init(Cipher.DECRYPT_MODE, pk);
    aesKey = new byte[AES_Key_Size/8];
    CipherInputStream is = new CipherInputStream(new FileInputStream(in), pkCipher);
    is.read(aesKey);
    aeskeySpec = new SecretKeySpec(aesKey, "AES");
  }
  /**
   * An example of how to use the code:
   * FileEncryption secure = new FileEncryption();
   * // to encrypt a file
   * secure.makeKey();
   * secure.saveKey(encryptedKeyFile, publicKeyFile);
   * secure.encrypt(fileToEncrypt, encryptedFile);
   * 
   * // to decrypt it again
   * secure.loadKey(encryptedKeyFile, privateKeyFile);
   * secure.decrypt(encryptedFile, unencryptedFile);
   */
}